#include "stdafx.h"

#include "Engine.h"

#define RANK_KING 10
#define RANK_MAN  3

#define DEFENCE_WEIGHT			25		// defence factor weight
#define MOBILITY_WEIGHT			6		// mobility weight
#define IMPORTANT_FIELD_WEIGHT	10		// important field weight
#define WING_BALANCE_WEIGHT		(-3)	// balance of game on both wings
#define ATTACKING_WEIGHT		5		// attacking weight
#define DEFENDING_WEIGHT		5		// defending weight


#define DEFENCE_MINIMUM_MEN		5		// the number of men required to compute the defence factor
#define MIN_TACTICS_NUM_MEN		6		// minimum number of men to calculate game tactics

 // DEBUG Men Advance Tables - are they good for anything?
///////////////////////////////////////////////////////////////////////////////////////////////////

volatile int wAdvanceFigurePos[32] = {1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8};
volatile int bAdvanceFigurePos[32] = {8,8,8,8,7,7,7,7,6,6,6,6,5,5,5,5,4,4,4,4,3,3,3,3,2,2,2,2,1,1,1,1};

volatile int wFigurePos64[50] = {1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8,9,9,9,9,9,10,10,10,10,10};
volatile int bFigurePos64[50] = {10,10,10,10,10,9,9,9,9,9,8,8,8,8,8,7,7,7,7,7,6,6,6,6,6,5,5,5,5,5,4,4,4,4,4,3,3,3,3,3,2,2,2,2,2,1,1,1,1,1};


 // Czech Piece-Square Tables - not very good test results
//////////////////////////////////////////////////////////////////////////////////////////////

volatile int wCzechPieceSquare[32] ={1,5,3,10,    1,1,5,1,   3,5,10,3,   10,10,10,1,   5,10,5,1, 0,0,0,0,
	0,0,0,0,   0,0,0,0

};
volatile int bCzechPieceSquare[32];

 // Czech attacking and defending fields
//////////////////////////////////////////////////////////////////////////////////////////////

const int attackFields = 7;
char* whiteAttackingFields[attackFields] = {"g1", "f2", "e3", "d4", "c5", "b6", "a7"};
uint32 whiteAttackingBB;

const int defendFields = 6;
char* whiteDefendingFields[defendFields] = {"c1", "d2", "e3", "f4", "g5", "h6"};
uint32 whiteDefendingBB;


 // Czech Men Patterns Tables
//////////////////////////////////////////////////////////////////////////////////////////////

#define PATTERN_WHITE				0		// white STM index
#define PATTERN_BLACK				1		// black STM index

#define STM_PATTERN_COUNT			2		// side to move count - DEBUG - for now just for white
#define MAX_MEN_PATTERN_COUNT		6		// maximum number of pieces for pattern

#define CZECH_PATTERN_COUNT			5		// number of patterns for Czech draughts

char* CzechPatternTable[CZECH_PATTERN_COUNT][MAX_MEN_PATTERN_COUNT] = 
{
	{"c1","e1","g1","d2","f2","e3"},		// Big Pyramid pattern
	{"c1","e1","d2","","",""},				// Small Pyramid pattern
	{"a3","b4","c5","","",""},				// Kolik
	{"e3","d4","c5","","",""},				// Kolik
	{"c5","d4","f4","","",""}				// Stonewall
};

volatile uint32 CzechPatternBB[STM_PATTERN_COUNT][CZECH_PATTERN_COUNT];

//bool CzechPatternDynamic[CZECH_PATTERN_COUNT] = {true, true, true, true};

volatile int CzechPatternCoefficient[CZECH_PATTERN_COUNT] = 
{ 
	5,	// Big Pyramid pattern
	10,	// Small Pyramid pattern
	15, // "Kolik"
	15, // "Kolik"
	15, // Stonewall
};

 // Important fields
////////////////////////////////////////////////////////////////////////////////

#define MAX_IMPORTANT_FIELDS	4

volatile int wCzechCheckersFields[MAX_IMPORTANT_FIELDS] = {17,13,1,3};
volatile int bCzechCheckersFields[MAX_IMPORTANT_FIELDS];

int ResolveImportantFields(uint32 men, int fieldCount, volatile int* fields)
{
	int sum = 0;

	// iterate through all men
	uint32 wm = men;
	while(wm)
	{
		int index = LSB(wm);

		for(int i = 0; i < fieldCount; i++)
			if(fields[i] == index)
				sum += IMPORTANT_FIELD_WEIGHT;

		wm = wm & (wm - 1);
	}

	return sum;
}

 // Initialization routines
////////////////////////////////////////////////////////////////////////////////////


// convert column
int ConvertColumn(char c)
{
	if(c == 'a')
		return 0;
	else if(c == 'b')
		return 1;
	else if(c == 'c')
		return 2;
	else if(c == 'd')
		return 3;
	else if(c == 'e')
		return 4;
	else if(c == 'f')
		return 5;
	else if(c == 'g')
		return 6;
	else if(c == 'h')
		return 7;
}

// converts coordinates
int ConvertCoordinates(char* c)
{
	int col = ConvertColumn(c[0]);
	int row = c[1] - '1';

	int index = row * 4;
	if(row % 2 == 0)
		col = col / 2;
	else
		col = (col - 1) / 2;

	index += col;
	return index;
}


void InitEvaluation()
{
	// convert piece-square tables == magic triangle
	for(int i = 0; i < 32; i++)
	{
		bCzechPieceSquare[31 - i] = wCzechPieceSquare[i];
	}

	// convert important fields
	for(int i = 0; i < MAX_IMPORTANT_FIELDS; i++)
	{
		bCzechCheckersFields[i] = 31 - wCzechCheckersFields[i];
	}

	// convert position patterns to bitboard
	for(int i = 0; i < CZECH_PATTERN_COUNT; i++)
	{
		// create pattern
		uint32 pattern = 0;
		for(int j = 0; j < MAX_MEN_PATTERN_COUNT; j++)
		{
			char* coor = CzechPatternTable[i][j];
			if(strlen(coor) == 0)
				break;

			int index = ConvertCoordinates(coor);
			pattern |= (1ul << index);
		}

		// set the pattern
		CzechPatternBB[PATTERN_WHITE][i] = pattern;
		CzechPatternBB[PATTERN_BLACK][i] = Revert(pattern);
	} // for

	// convert attacking strategy
	uint32 pattern = 0;
	for(int i = 0; i < attackFields; i++)
	{
		int index = ConvertCoordinates(whiteAttackingFields[i]);
		pattern |= (1 << index);
	}
	whiteAttackingBB = pattern;

	// convert defending strategy
	pattern = 0;
	for(int i = 0; i < defendFields; i++)
	{
		int index = ConvertCoordinates(whiteDefendingFields[i]);
		pattern |= (1 << index);
	}
	whiteDefendingBB = pattern;
}

 // Men Pattern Evaluation - DEBUG - just for 32-bits checkers
////////////////////////////////////////////////////////////////////////////////////

int EvaluateMenPatterns(uint32 men, int patternCount, volatile uint32* tblPattern, volatile int* tblCoef)
{
	// DEBUG - convert to the MAX_PATTERN_COUNT
	int values[CZECH_PATTERN_COUNT];
	assert(patternCount <= CZECH_PATTERN_COUNT);
	memset(values, 0, sizeof(int) * CZECH_PATTERN_COUNT);

	// if no men, exit
	if(LSB(men) < 0)
		return 0;
	
	uint32 wm = men;

	// iterate through all patterns
	for(int i = 0; i < patternCount; i++)
	{
		values[i] = BitCount(tblPattern[i] & wm);
	}

	// calculate weighted sum of all patterns
	int sum = 0;
	for(int i = 0; i < patternCount; i++)
	{
		//if(CzechPatternDynamic[i])
		//	sum += values[i] * tblCoef[i];
		//else
			//if(values[i] == CzechPatternCount[i])
				sum += values[i] * tblCoef[i];
	}

	return sum;
}

 // Game Tactics
////////////////////////////////////////////////////////////////////////////////


#define WHITE_LEFT_WING		0xCCCC
#define WHITE_RIGHT_WING	0x3333

// magic triangle for developing position in the opening of game
// valid for 8-10 pieces
int CalculateMagicTriangle(uint32 men, volatile int* magicTriangleFields)
{
	int value = 0;

	while(men)
	{
		int index = LSB(men);
		value += magicTriangleFields[index];

		men = men & (men - 1);
	}

	return value;
}

// calculate wing balance
int CalculateWingBalance(uint32 men)
{
	int leftWingCount = BitCount(men & WHITE_LEFT_WING);
	int rightWingCount = BitCount(men & WHITE_RIGHT_WING);
	return WING_BALANCE_WEIGHT * abs(leftWingCount - rightWingCount);
}

// calculate attack weight value
int CalculateAttackValue(uint32 men)
{
	return ATTACKING_WEIGHT * BitCount(men & whiteAttackingBB);
}

// calculate defending value
int CalculateDefendValue(uint32 men)
{
	return DEFENDING_WEIGHT  * BitCount(men & whiteDefendingBB);
}

 // evaluation function templates
////////////////////////////////////////////////////////////////////////////////////

template<typename TBITBOARD> int Evaluation(SEngineData* ed, TBITBOARD* bb, bool bWhite)
{
	return 0;
}

template<> int Evaluation<BitBoard>(SEngineData* ed, BitBoard* bb, bool bWhite)
{
	return ed->Evaluation32Ptr(ed, bb, bWhite);
}

template<> int Evaluation<BitBoard64>(SEngineData* ed, BitBoard64* bb, bool bWhite)
{
	return ed->Evaluation64Ptr(ed, bb, bWhite);
}

 // evaluation functions
///////////////////////////////////////////////////////////////////////////////////////

int BasicEvaluation(SEngineData *ed, BitBoard* bb, bool bWhite)
{
	 // calculate men counts
	/////////////////////////////////////
	int wMenCount = BitCount(bb->wm);
	int bMenCount = BitCount(bb->bm);

	 // material values for both sides
	/////////////////////////////////////
	int wValue = wMenCount * MAN_VALUE + BitCount(bb->wk) * KING_VALUE;
	int bValue = bMenCount * MAN_VALUE + BitCount(bb->bk) * KING_VALUE;

	 // men propagation to the promotion line
	///////////////////////////////////////////
	uint32 wm = bb->wm;
	while(wm)
	{
		int index = LSB(wm);
		wValue += wAdvanceFigurePos[index];
		wm = wm & (wm - 1);
	}

	uint32 bm = bb->bm;
	while(bm)
	{
		int index = LSB(bm);
		bValue += bAdvanceFigurePos[index];
		bm = bm & (bm - 1);
	}

	// check, if position evaluation is allowed
	if(ed->bUsePositionEvaluation == false)
	{
		// if not position strategy, evaluate only material and men propagation
		return bWhite ? wValue - bValue : bValue - wValue;
	}

	 // evaluate magic-triangle field
	/////////////////////////////////////////////
	if(wMenCount >= 8 && wMenCount <= 11)
	{
		wValue += CalculateMagicTriangle(bb->wm, wCzechPieceSquare);
	}
	if(bMenCount >= 8 && bMenCount <= 11)
	{
		bValue += CalculateMagicTriangle(bb->bm, bCzechPieceSquare);
	}

	 // resolve basic static patterns of men
	//////////////////////////////////////////////
	
	wValue += EvaluateMenPatterns(bb->wm, CZECH_PATTERN_COUNT, &(CzechPatternBB[PATTERN_WHITE][0]), CzechPatternCoefficient);
	bValue += EvaluateMenPatterns(bb->bm, CZECH_PATTERN_COUNT, &(CzechPatternBB[PATTERN_BLACK][0]), CzechPatternCoefficient);

	 // calculate defence factor
	/////////////////////////////////////////////
	
	//if(wMenCount > DEFENCE_MINIMUM_MEN)
	//	wValue += CzechMoveGen::CalculateDefenceFactor(bb->wm, true) * DEFENCE_WEIGHT;
	//if(bMenCount > DEFENCE_MINIMUM_MEN)
	//	bValue += CzechMoveGen::CalculateDefenceFactor(bb->bm, false) * DEFENCE_WEIGHT;

	 // resolve important fields
	//////////////////////////////////////////////
	
	wValue += ResolveImportantFields(bb->wm, MAX_IMPORTANT_FIELDS, wCzechCheckersFields);
	bValue += ResolveImportantFields(bb->bm, MAX_IMPORTANT_FIELDS, bCzechCheckersFields);

	 // calculate mobility factor
	//////////////////////////////////////////////

	int moveCount = 0;
	moveCount = CzechMoveGen::CalculateMenMobility(bb, true);
	wValue += moveCount * MOBILITY_WEIGHT;

	moveCount = CzechMoveGen::CalculateMenMobility(bb, false);
	bValue += moveCount * MOBILITY_WEIGHT;

	
	//// FUTURE INVESTIGATION ON GAME STRATEGY, FOR NOW MAKES WORSE RESULTS
	//// calculate game strategy
	//if(wMenCount > MIN_TACTICS_NUM_MEN)
	//{
	//	// calculate wing balance
	//	//wValue += CalculateWingBalance(bb->wm);

	//	//// choose playing strategy
	//	//if(wMenCount >= bMenCount)
	//	//{
	//	//	// attacking strategy
	//	//	wValue += CalculateAttackValue(bb->wm);
	//	//}
	//	//else
	//	//{
	//	//	// defending strategy
	//	//	wValue += CalculateDefendValue(bb->wm);
	//	//}
	//}


	return bWhite ? wValue - bValue : bValue - wValue;
}

int BasicEvaluation64(SEngineData *ed, BitBoard64* bb, bool bWhite)
{
	// material
	int wValue = BitCount64(bb->wm) * MAN_VALUE + BitCount64(bb->wk) * KING_VALUE;
	int bValue = BitCount64(bb->bm) * MAN_VALUE + BitCount64(bb->bk) * KING_VALUE;

	// white position
	uint64 wm = bb->wm;
	while(wm)
	{
		wValue += wFigurePos64[LSB64(wm)];
		wm = wm & (wm - 1);
	}

	// black position
	uint64 bm = bb->bm;
	while(bm)
	{
		bValue += bFigurePos64[LSB64(bm)];
		bm = bm & (bm - 1);
	}

	return bWhite ? wValue - bValue : bValue - wValue;
}



int GetDBRank(BitBoard bb, bool bWhite)
{
	int wk = BitCount(bb.wk);
	int bk = BitCount(bb.bk);
	int wm = BitCount(bb.wm);
	int bm = BitCount(bb.bm);
	int wmrank = MSB(bb.wm);
	int bmrank = 31 - LSB(bb.bm);

	int wRank = wk * RANK_KING + wm * RANK_MAN + wmrank;
	int bRank = bk * RANK_KING + bm * RANK_MAN + bmrank;

	return bWhite ? wRank - bRank : bRank + wRank;
}

bool IsPromotingMan(BitBoard* bb, bool bWhite)
{
	if(bWhite)
	{
		return MSB(bb->wm) / 4 > 5;
	}
	else
		return (31-LSB(bb->bk)) / 4 > 5;
}

  // Position evaluation got from Martin Fierz in simplech.c engine converted to bitboard evaluation
 // Source downloadable by installing CheckersBoard program
////////////////////////////////////////////////////////////////////////////////////////////////////////
//int PositionEvaluation(BitBoard* bb, bool bWhite, ZOBRIST_KEY zkeyBoard)
//{
//	int value;
//	if(EvalCache_Lookup(zkeyBoard, &value) == true)
//	{
//		return value;
//	}
//
//
//	// count of figures
//	int numWM = BitCount(bb->wm);
//	int numWK = BitCount(bb->wk);
//	int numBM = BitCount(bb->bm);
//	int numBK = BitCount(bb->bk);	
//	int numM = numWM + numBM;
//	int numK = numWK + numBK;
//
//	// material evaluation
//	int whiteMat = numWM * MAN_VALUE + numWK * KING_VALUE;
//	int blackMat = numBM * MAN_VALUE + numBK * KING_VALUE;
//
//	int whiteEval = whiteMat - blackMat;
//	// favor material exchange if in plus
//	//whiteEval += ( (MAN_VALUE + KING_VALUE + 20) * (whiteMat - blackMat)) / (whiteMat + blackMat);
//
//	// side to move gets "turn value" favor
//	int turn = 2;
//	if(bWhite == true) whiteEval += turn;
//	else whiteEval -= turn;
//
//	// evaluate cramp field attack
//	int crampValue = 5;
//	if( (bb->wm & (1 << 16)) && (bb->bm & (1 << 20))) whiteEval += crampValue;
//	if( (bb->bm & (1 << 15)) && (bb->wm & (1 << 11))) whiteEval -= crampValue;
//
//	// back rank guard
//	int code = 0;
//	
//	// white back rank guard - get combination of bank rank
//	if(bb->wm & (1 << 0)) code++;
//	if(bb->wm & (1 << 1)) code+=2;
//	if(bb->wm & (1 << 2)) code+=4;
//	if(bb->wm & (1 << 3)) code+=8;
//
//	// evaluate combination of back rank guard
//	switch (code)
//	{
//	case 0: code=0;break;
//	case 1: code=-1;break;
//	case 2: code=1;break;
//	case 3: code=0;break;
//	case 4: code=1;break;
//	case 5: code=1;break;
//	case 6: code=2;break;
//	case 7: code=1;break;
//	case 8: code=1;break;
//	case 9: code=0;break;
//	case 10: code=7;break;
//	case 11: code=4;break;
//	case 12: code=2;break;
//	case 13: code=2;break;
//	case 14: code=9;break;
//	case 15: code=8;break;
//	}
//	int backrank=code;
//
//	// black back rank guard - get combination of bank rank
//	code = 0;
//	if(bb->bm & (1 << 28)) code+=8;
//	if(bb->bm & (1 << 29)) code+=4;
//	if(bb->bm & (1 << 30)) code+=2;
//	if(bb->bm & (1 << 31)) code++;
//
//	// evaluate combination
//	switch (code)
//	{
//	case 0: code=0;break;
//	case 1: code=-1;break;
//	case 2: code=1;break;
//	case 3: code=0;break;
//	case 4: code=1;break;
//	case 5: code=1;break;
//	case 6: code=2;break;
//	case 7: code=1;break;
//	case 8: code=1;break;
//	case 9: code=0;break;
//	case 10: code=7;break;
//	case 11: code=4;break;
//	case 12: code=2;break;
//	case 13: code=2;break;
//	case 14: code=9;break;
//	case 15: code=8;break;
//	}
//
//	backrank-=code;
//	
//	// add combination of bank rank by multiplier
//	const int brv=3;
//	whiteEval +=  brv * backrank;
//
//	// intact double-corner attack field
//	const int intactdoublecorner=3;
//	if( bb->wm & (1 << 3))
//	{
//		if( (bb->bm & (1 << 6)) || (bb->bm & (1 << 7)))
//			whiteEval += intactdoublecorner;
//	}
//	if( bb->bm & (1 << 31))
//	{
//		if( (bb->wm & (1 << 24)) || (bb->wm & (1 << 25)))
//			whiteEval -= intactdoublecorner;
//	}
//
//	// center position occupancy
//	int numWhiteManCenter = 0;
//	int numBlackManCenter = 0;
//	int center[8]={9,10,13,14,17,18,21,22}; // center fields
//	const int mcv=1; //multiplier for men in center
//	for(int i=0;i<8;i++)
//	{
//		if(bb->wm & (1 << center[i]) ) numWhiteManCenter++;
//		if(bb->bm & (1 << center[i]) ) numBlackManCenter++;
//	}
//	whiteEval += (numWhiteManCenter - numBlackManCenter) * mcv;
//
//	// edge position occupancy
//	int edge[14]={0,1,2,3,7,8,15,16,23,24,27,28,30,31};
//	const int mev=1;    //multiplier for men on edge
//	int numWhiteManEdge = 0;
//	int numBlackManEdge = 0;
//	for(int i=0;i<14;i++)
//	{
//		if(bb->wm & (1 << edge[i]) ) numWhiteManEdge++;
//		if(bb->bm & (1 << edge[i]) ) numBlackManEdge++;
//	}
//	whiteEval += (numWhiteManEdge - numBlackManEdge) * mev;
//
//	// evaluate tempo of men according to the game phase (opening, middle game, endgame)
//	int tempo = 0;
//	const int opening=-2; // multipliers for tempo
//	const int midgame=-1;
//	const int endgame=2;
//	int row[32]={0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7};
//	for(int i=0; i<32; i++)
//	{
//		if(bb->wm & (1 << i))
//			tempo+=row[i];
//		if(bb->bm & (1 << i))
//			tempo-=7-row[i];
//	}
//	if(numM >= 16) whiteEval+=opening*tempo;
//	if((numM <= 15) && (numM>=12)) whiteEval+=midgame*tempo;
//	if(numM < 9) whiteEval+=endgame*tempo;
//
//	// evaluate the system of stones
//	//int stonesinsystem = 0;
//	//uint32 occupied = bb->wm | bb->bm;
//	//if(numWM + numWK - numBM - numBK == 0)
//	//{
//	//	if(bWhite)
//	//	{
//	//		for(int i=0; i<=3; i++)
//	//		{
//	//			for(int j=0; j<4; j++)
//	//			{
//	//				int shift = i + (j << 3);
//	//				if(occupied & (1 << shift)) stonesinsystem++;
//	//			}
//	//		}
//	//		if(stonesinsystem % 2)
//	//		{
//	//			if(numM+numK<=12) whiteEval++;
//	//			if(numM+numK<=10) whiteEval++;
//	//			if(numM+numK<=8) whiteEval+=2;
//	//			if(numM+numK<=6) whiteEval+=2;
//	//		}
//	//		else
//	//		{
//	//			if(numM+numK<=12) whiteEval--;
//	//			if(numM+numK<=10) whiteEval--;
//	//			if(numM+numK<=8) whiteEval-=2;
//	//			if(numM+numK<=6) whiteEval-=2;
//	//		}
//	//	}
//	//	else
//	//	{
//	//		for(int i=4; i<=7; i++)
//	//		{
//	//			for(int j=0; j<4; j++)
//	//			{
//	//				int shift = i + (j << 3);
//	//				if(occupied & (1 << shift)) stonesinsystem++;
//	//			}
//	//		}
//	//		if((stonesinsystem % 2) == 0)
//	//		{
//	//			if(numM+numK<=12) whiteEval++;
//	//			if(numM+numK<=10) whiteEval++;
//	//			if(numM+numK<=8) whiteEval+=2;
//	//			if(numM+numK<=6) whiteEval+=2;
//	//		}
//	//		else
//	//		{
//	//			if(numM+numK<=12) whiteEval--;
//	//			if(numM+numK<=10) whiteEval--;
//	//			if(numM+numK<=8) whiteEval-=2;
//	//			if(numM+numK<=6) whiteEval-=2;
//	//		}
//	//	}
//	//}
//
//	// choose sign of evaluation by side to move
//	int eval = bWhite ? whiteEval : -whiteEval;
//
//	EvalCache_Store(zkeyBoard, eval);
//
//	return eval;
//}


 // setting the evaluation function according to the checkers type
/////////////////////////////////////////////////////////////////////////////////////////////////////

void SetCheckersTypeEval(SEngineData* ed, eCheckersType type)
{
	ed->wPieceSquareTable = NULL;
	ed->bPieceSquareTable = NULL;

	switch(type)
	{
	case CzechCheckers:
		ed->Evaluation32Ptr = BasicEvaluation;		
		// set piece-square tables
		//ed->wPieceSquareTable = wCzechPieceSquare;
		//ed->bPieceSquareTable = bCzechPieceSquare;
		break;
	case EnglishCheckers:
		ed->Evaluation32Ptr = BasicEvaluation;		
		break;
	case InternationalCheckers:
		ed->Evaluation64Ptr = BasicEvaluation64;
		break;
	default:
		assert(false);
	}
}
